import com.alibaba.fastjson.JSON
import exceptions.BilibiliException
import exceptions.VideoNotFoundException
import java.io.IOException
import java.net.URL
import java.sql.Connection
import java.sql.SQLException
import java.text.SimpleDateFormat
import java.util.*

/**
 * 入口
 */
object Laucher {
    @JvmStatic
    fun main(args: Array<String>) {
        printInfo() // 打印信息
        if (LocalDatabase.connection == null) {
            return
        }

        val timer = Timer(true)
        timer.schedule(object : TimerTask() {
            override fun run() {
                Thread {
                    refresh(LocalDatabase.connection)
                }.start()
                System.gc()
            }
        }, 1000, 60000)
        Thread.sleep(3000L * 24 * 3600 * 1000)
    }

    /**
     * 周期性刷新
     */
    @kotlin.jvm.Throws(SQLException::class)
    fun refresh(connection: Connection) {
        /**
         * 在终端打印当前状态
         */
        val df = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        print("[${df.format(Date())}]")

        /**
         * 获取当前监测任务列表
         */
        val taskList = mutableListOf<Int>()
        val pQuery = connection.prepareStatement("SELECT * FROM task_list;").apply {
            executeQuery()
        }
        val resultSet = pQuery.resultSet
        while (resultSet.next()) {
            taskList.add(resultSet.getInt("aid"))
        }
        pQuery.close()

        /**
         * 获取Bilibili数据
         */
        var count = 0;
        for (aid in taskList) {
            try {
                val data: VideoData = getVideoData(aid)
                connection.prepareStatement("INSERT INTO video_record(added, aid, view, danmaku, reply, favorite, coin, share, `like`) VALUES (UNIX_TIMESTAMP(),?, ?,?,?,?,?,?,?);")
                    .apply {
                        setInt(1, aid)
                        setInt(2, data.view)
                        setInt(3, data.danmaku)
                        setInt(4, data.reply)
                        setInt(5, data.favorite)
                        setInt(6, data.coin)
                        setInt(7, data.share)
                        setInt(8, data.like)
                        executeUpdate()
                    }
                count++
            } catch (e: IOException) {
                System.err.println("【异常】网络连接异常。")
            } catch (e: VideoNotFoundException) {
                System.err.println("【异常】视频AV${aid}不存在。")
            } catch (e: BilibiliException) {
                System.err.println("【异常】exceptions.BilibiliException\n")
                e.printStackTrace(System.err)
            }
        }

        print(" 获取视频数据完毕。共有${taskList.size}项任务，成功${count}项。\n")
    }

    /**
     * 根据AV号获取视频数据
     *
     * @param aid 欲读取的视频AV号
     * @return VideoData对象
     */
    @kotlin.jvm.Throws(IOException::class, VideoNotFoundException::class, BilibiliException::class)
    private fun getVideoData(aid: Int): VideoData {
        val apiString = readApi(urlPath = "https://api.bilibili.com/x/web-interface/archive/stat?aid=$aid")
        val jsonObject = JSON.parseObject(apiString)
        val code = jsonObject.getIntValue("code")
        if (code == -404) {
            throw VideoNotFoundException(aid)
        } else if (code != 0) {
            throw BilibiliException(aid)
        }
        val data = jsonObject.getJSONObject("data")
        return VideoData(
            aid = aid,
            view = data.getIntValue("view"),
            danmaku = data.getIntValue("danmaku"),
            reply = data.getIntValue("reply"),
            favorite = data.getIntValue("favorite"),
            coin = data.getIntValue("coin"),
            share = data.getIntValue("share"),
            like = data.getIntValue("like")
        )
    }


    /**
     * 读取B站API，输入欲读取API的URL地址，返回读出来的文本。
     *
     * @param urlPath 欲读取的API地址
     * @return 返回读出来的文本（String）
     * @throws IOException 使用stream导致的Exception
     */
    @kotlin.jvm.Throws(IOException::class)
    private fun readApi(urlPath: String): String {
        val url = URL(urlPath)
        val inputStream = url.openStream()
        val bytes = ByteArray(inputStream.available())
        inputStream.read(bytes)
        val str = String(bytes)
        inputStream.close()
        return str
    }

    fun printInfo() {
        println(
            """寒棠Hantang Bilibili数据记录器
版　　本：2.0
制　　作：景育
编译日期：2021年10月18日
=========================================
"""
        )
    }
}